#include <regex>
#include <string>
#include <optional>
#include <iostream>

namespace plate_validating
{
std::regex pattern(R"([A-Z]{2}\d{3,4})");
std::regex ex(R"((\b[A-Z]{2}\d{4,5}\b)*)");

bool validate(const std::string& str)
{
    return std::regex_match(str.data(), pattern);
}

std::vector<std::string> extract(const std::string& str)
{
    std::smatch m;
    std::vector<std::string> result;
    for (auto i = std::sregex_iterator(str.cbegin(), str.cend(), ex);
         i != std::sregex_iterator();
         ++i)
    {
        if ((*i)[1].matched)
        {
            result.push_back(i->str());
        }
    }
    return result;
}

}  // namespace plate_validating

namespace url_extract
{
struct url_parts
{
    std::string protocol;
    std::string domain;
    std::optional<int> port;
    std::optional<std::string> path;
    std::optional<std::string> query;
    std::optional<std::string> fragment;
};

/**
 * @brief
 * protocal ^(\w+):
 * domain ([\w.-]+)
 * port (:(\d+))?
 * path ([\w\/\.]+)?
 * query + fragment (\?([\w=&]*)(#?(\w+))?)?
 */
std::regex rx(
    R"(^(\w+):\/\/([\w.-]+)(:(\d+))?([\w\/\.]+)?(\?([\w=&]*)(#?(\w+))?)?$)");

std::optional<url_parts> parse(const std::string& url)
{
    std::smatch m{};
    if (std::regex_match(url, m, rx))
    {
        if (m[1].matched && m[2].matched)
        {
            url_parts parts{};
            parts.protocol = m[1].str();
            parts.domain = m[2].str();
            if (m[4].matched)
            {
                parts.port = std::stoi(m[4]);
            }
            if (m[5].matched)
            {
                parts.path = m[5].str();
            }
            if (m[7].matched)
            {
                parts.query = m[7].str();
            }
            if (m[9].matched)
            {
                parts.fragment = m[9].str();
            }
            return parts;
        }
    }
    return {};
}
}  // namespace url_extract

namespace date_transform
{
std::regex rx(R"((\d{1,2})(\.|-|/)(\d{1,2})(\.|-|/)(\d{4}))");
std::string func(const std::string& text)
{
    return std::regex_replace(text.c_str(), rx, R"($5-$3-$1)");
}
}  // namespace date_transform

using namespace std;

auto print_matched = [](auto const& cont) {
    cout << "Matched " << cont.size() << " results:\n";
    for (auto const& i : cont)
    {
        cout << "\t" << i << '\n';
    }
};

int main(int argc, char** argv)
{
    string plates = "BF33126, B3321, AC1234, A1688, DFE1234";
    print_matched(plate_validating::extract(plates));
    string url = "https://bbc.com:80/en/index.html?lite=true#ui";
    auto parts = url_extract::parse(url);
    auto print_parts = [](const url_extract::url_parts& p) {
        cout << "protocol: " << p.protocol << '\n';
        cout << "domain: " << p.domain << '\n';
        cout << "port: " << p.port.value() << '\n';
        cout << "path: " << p.path.value() << '\n';
        cout << "query: " << p.query.value() << '\n';
        cout << "fragment: " << p.fragment.value() << '\n';
    };

    print_parts(parts.value());

    string date_text = "today is 07/09/2021";
    cout << date_transform::func(date_text) << '\n';

    return 0;
}